from objc import Category
from AppKit import NSBezierPath
import math


_elementNames = ['MoveTo', 'LineTo', 'CurveTo', 'ClosePath']

def poly_point(center, r, degrees):
    x = r * math.cos(degrees) + center[0]
    y = r * math.sin(degrees) + center[1]
    return x,y

def polypoints(center, r, numPoints, degreesRotation=0):
    if numPoints < 3: raise ValueError, 'Must have at least 3 points in a polygon'
    rotation = math.radians(degreesRotation)
    theta = (math.pi * 2) / numPoints
    return [poly_point(center, r, i*theta+rotation) for i in range(numPoints)]
 

class NSBezierPath(Category(NSBezierPath)):
    
    @classmethod
    def bezierPathWithCircleOrigin_radius_(cls, center, radius):
        x,y = center
        rect = (x-radius, y-radius), (radius * 2, radius * 2)
        return cls.bezierPathWithOvalInRect_(rect)

    def points(self):
        points = []
        for i in range(self.elementCount()):
            elem, pts = self.elementAtIndex_associatedPoints_(i)
            points += pts
        return points

    def elements(self):
        return [self.elementAtIndex_(i) for i in range(self.elementCount())]


    def elementAsTextAtIndex_(i):
        return _elementNames[self.elementAtIndex_(i)]

    def elementsAsText(self):
        return [self.elementAsTextAtIndex_(i) for i in range(self.elementCount())]

    def appendBezierPathWithPolygonWithCenter_radius_numberOfPoints_(self, center, radius, numberOfPoints):
        '''
        Creates a regular polygon
        '''
        pts = polypoints(center, radius, numberOfPoints)
        self.moveToPoint_(pts[0])
        for pt in pts[1:]:
            self.lineToPoint_(pt)
        self.closePath()


    def appendBezierPathWithPolygonWithCenter_radius_numberOfPoints_rotationInRadian_(self, center, radius, numberOfPoints, radians):
        pts = polypoints(center, radius, numberOfPoints, radians)
        self.moveToPoint_(pts[0])
        for pt in pts[1:]:
            self.lineToPoint_(pt)
        self.closePath()

    def dot(self):
        '''
        Similar to stroke: and fill:, but draws dots for each point in the
        path.  Dot size is based on linewidth. Not as efficient, because it
        creates a separate NSBezierPath each time it is called.
        '''
        tmp_path = NSBezierPath.alloc().init()
        width = self.lineWidth()
        offset = width / 2
        for point in self.points():
            rect = (point[0] - offset, point[1] - offset),(width, width)
            tmp_path.appendBezierPathWithOvalInRect_(rect)
        tmp_path.fill()

